﻿//===========================[ 8 / 2 / 2011 LVI ]=============================
//				Copyright c Vitaly Lyaschenko <SkyChameleon@gmail.com>
//								Source file
// Purpose: 
//=============================================================================
#include "Shape.h"
#include "Kernel.h"

Shape::Shape() : 
    m_Model(NULL),
    m_pEffect(NULL),
    m_pRender(NULL),
    m_VAO(NULL),
    m_VBO_Pos(NULL),
    m_VBO_Normal(NULL),
    m_VBO_TexCoor(NULL),
    m_VBO_Indices(NULL),
    m_buildFlag(false)
{	
    m_pRender = Kernel::spec().getRender();
    m_pScript = Kernel::spec().getScript();
}

Shape::~Shape()
{
    release();
}

bool Shape::init( const std::string& fileName, cEffect *pEffect, bool buildFlag )
{
    if ( !m_pScript->doScript( cFileManager::lookUpPath(fileName).c_str() ) )
        return false;

    std::string strToMesh = cFileManager::lookUpPath( m_pScript->getGlobalS("patch_Mesh") );

    this->m_pEffect = pEffect;
    
    m_Model = cMeshesManager::loadMesh( strToMesh );

    std::string strToImage = cFileManager::lookUpPath( m_pScript->getGlobalS("patch_Texture") );
    // создаем и загружаем изображение
    cImage img;
    img.loadImage( strToImage );
    // создаем 2D текстуру
    m_Texture = m_pRender->createTexture( glLINEAR, glLINEAR, /*glREPEAT*/glCLAMP_TO_EDGE, glTEXTURE_2D, &img );
    if ( buildFlag )
        build();

    return true;
}

void Shape::build()
{
    // если ранее модель не "собиралась"
    if (!m_buildFlag)
    {
        // берем uniform 2D текстуры из шейдерной программы
        m_Texture->setLocationInProgram( m_pEffect->Program()->getLocationUniform( "material.color2DTexture") );
        // активизируем текстурный unit
        m_pRender->setTexture( m_Texture, m_pEffect->Program(), 0 );
        m_Texture->UnbindTexture();

        for ( int i=0; i != m_Model->getNumMesh(); i++ )
        {   
            int sizeofVert = sizeof(Vertex_PNT) * m_Model->meshes[i]->getNumVertices();
            int sizeofIndx = sizeof(_16ubit) * m_Model->meshes[i]->getNumIndices();
            void *dataVert = m_Model->meshes[i]->m_Vertices.data();
            void *dataIndx = m_Model->meshes[i]->m_Indices.data();

            // создание и биндинг 1 VAO для части модели
            m_VAO.push_back( m_pRender->createVArray() );
            m_VAO.back()->Create();

            // создаем VBO(Vertex Buffer Object) для позиции вершин
            m_VBO_Pos.push_back( m_pRender->createVBuffer( sizeofVert, dataVert ) );
            m_pRender->setAttrPtr( VERT_POSITION, 3, sizeof(Vertex_PNT), (void *)0 );

            // создаем VBO(Vertex Buffer Object) для нормалей
            m_VBO_Normal.push_back( m_pRender->createVBuffer( sizeofVert, dataVert ) );
            m_pRender->setAttrPtr( VERT_NORMAL, 3, sizeof(Vertex_PNT), (void *)(sizeof(float) * 3) );

            // создаем VBO(Vertex Buffer Object) для текстурных координат
            m_VBO_TexCoor.push_back( m_pRender->createVBuffer( sizeofVert, dataVert ) );
            m_pRender->setAttrPtr( VERT_TEXCOORD, 2, sizeof(Vertex_PNT), (void *)(sizeof(float) * 6) );

            // создаем VBO(Vertex Buffer Object) для индексов
            m_VBO_Indices.push_back( m_pRender->createVBufferEl( sizeofIndx, dataIndx ) );

            m_VAO.back()->Unbind();
        }
        m_buildFlag = true;
    }
}

void Shape::draw()
{
    m_pEffect->setMtrModel( mtrModel * scale1 );

    m_pRender->setDrawPrimitiveMode( Triangles );
    m_Texture->BindTexture(0);

    auto it = m_VAO.begin();
    for (int i = 0 ; it != m_VAO.end(); it++, i++ )
    {
        int coutIndx = m_Model->meshes[i]->getNumIndices(); // TODO: / modify !
        (*it)->Bind();
        m_pRender->drawElements16(coutIndx);
        (*it)->Unbind();
    }
    m_Texture->UnbindTexture();
}

///////////////////////////////////////////////////////////////////////////
// освобождение всех ресурсов
void Shape::release()
{
    if (!m_buildFlag)
        return;

    for ( int i=0; i != m_Model->getNumMesh(); i++ )
    {   
        // освобождение всех VBO
        m_VBO_Pos.at(i)->Release();
        m_VBO_Normal.at(i)->Release();
        m_VBO_TexCoor.at(i)->Release();
        m_VBO_Indices.at(i)->Release();

        // удаление VAO
        m_VAO.at(i)->Release();
    }

    m_VAO.clear();
    m_VBO_Pos.clear();
    m_VBO_Normal.clear();
    m_VBO_TexCoor.clear();
    m_VBO_Indices.clear();

    SAFE_DELETE( m_Model );

    SAFE_DELETE( m_Texture );

    m_buildFlag = false;
}